
/**
 * @namespace DOM
 */
(function() {

	__Document = null;

	G.Namespace('DOM');

	/**
	 * The externtions to standard DOM.
	 * @namespace DOM
	 * @class Element
	 */
	G.GClass('DOM', 'Element', G.Base.EventListener);

	/**
	 * Constructure of DOM.Element
	 * @function __init
	 */
	G.DOM.Element.prototype.__init = function(element) {
		if (!element) {
			throw new Error("Can't create DOM.Element on a undefined object");
		}

		this.__Base__EventListener__init();
		this.em = element;
	};

	/**
	 *
	 * Get the mouse position offset to body of page in event report
	 * @method get_mouse
	 * @param ev {Event} The mouse event
	 */
	G.DOM.Element.prototype.get_mouse = function(ev) {
		if (ev.pageX || ev.pageY) {
			return {x:ev.pageX, y: ev.pageY};
		}
		return {
			x: ev.clientX - document.body.scrollLeft - document.body.clientLeft,
			y: ev.clientY - document.body.scrollTop - document.body.clientTop
		}
	}

	/**
	 * Get the top/left of the element offset to the page.
	 * @method get_offset_in_page
	 * @return {object} the 
	 */
	G.DOM.Element.prototype.get_offset_in_page = function() 
	{
		var l = this.em.offsetLeft;
		var t = this.em.offsetTop;

		for (p = this.em.offsetParent; (p != null && p.tagName != "body"); p = p.offsetParent){
			l += p.offsetLeft;
			t += p.offsetTop; 
		}
		return {'left': l, 'top': t};
	}

	G.DOM.Element.prototype.__listen = function(evname) 
	{
		if (evname == "onresize") {
			this.reg_resize_check();
		} else if (evname == "ondrag") {
			this.enable_drag();
		} else {
			var _self = this;

			if (window.addEventListener) {
				this.em.addEventListener(evname.substr(2), function(ev) {
					ev = ev || window.event;
					ev.srcElement = ev.srcElement || ev.target;
					_self.fire(evname, ev);
				}, false);
			} else {
				this.em.attachEvent(evname, function(ev) {
					ev = ev || window.event;
					ev.srcElement = ev.srcElement || ev.target;
					_self.fire(evname, ev);
				});
			}
		}
	}

	G.DOM.Element.prototype.__unlisten = function(evname) {
		if (evname == "onresize") {
			this.unreg_resize_check();
		} else {
			this.em[evname] = null;
		}
	}
})();


/*
 * ============================= Drag ====================================
 */
(function(){

	var _dragObj = null;
	var _mouseOffset = null;
	var _dragOrig = {x: 0, y: 0};
	var _mouseOrig = {x: 0, y: 0};
	var _lastPosition = {x:0, y:0};
	var _dragLimit = null;
	var _monitorMouseUp = false;

	function on_mouse_move(ev) {
		ev = ev || window.event;

		if (window.getSelection) {
			window.getSelection().removeAllRanges();
		}

		if (_dragObj) {
			var pos = G(document).get_mouse(ev);
			var t = _dragOrig.y + (pos.y - _mouseOrig.y);
			var l = _dragOrig.x + (pos.x - _mouseOrig.x);

			if (t < _dragLimit.minY)	t = _dragLimit.minY;
			if (t > _dragLimit.maxY)	t = _dragLimit.maxY;

			if (l < _dragLimit.minX)	l = _dragLimit.minX;
			if (l > _dragLimit.maxX)	l = _dragLimit.maxX;

			if (t != _lastPosition.y || l != _lastPosition.x) {
				_dragObj.em.style.top = t;
				_dragObj.em.style.left = l;

				_lastPosition.y = t;
				_lastPosition.x = l;

				_dragObj.fire("ondrag", {'top': t, 'left': l});
			}
		}
	}

	function on_mouse_up() {
		_dragObj = null;
	}

	function get_limit(em) {
		p = em.parentNode;

	}

	var _drag_mouse_down = function(ev) {
		ev = ev || window.event;
		em = ev.srcElement || ev.target;

		// Limit the drag in parent's client area.
		var p = em.parentNode;
		var areaW = p.clientWidth;
		var areaH = p.clientHeight;
		_dragLimit = {
			minX: 0,
			maxX: areaW - em.offsetWidth,
			minY: 0,
			maxY: areaH - em.offsetHeight
		}

		_dragObj = this;
		_dragOrig.x = em.offsetLeft;
		_dragOrig.y = em.offsetTop;
		_lastPosition.x = _dragOrig.x;
		_lastPosition.y = _dragOrig.y;

		_mouseOrig = G(document).get_mouse(ev);
		G(document).bind("onmousemove", on_mouse_move);
	}

	/**
	 * Enable the drag ability of the DomElement
	 * @method enable_drag
	 */
	G.DOM.Element.prototype.enable_drag= function() {
		if (!_monitorMouseUp) {
			G(document).bind("onmouseup", on_mouse_up);
		}
		this.bind("onmousedown", _drag_mouse_down);
	}

	/**
	 * Disable the drag ability of the DomElement
	 * @method disable_drag
	 */
	G.DOM.Element.prototype.disable_drag = function() {
		this.unbind("onmousedown", _drag_mouse_down);
	}

})();


/*
 * ============================= Resize ====================================
 */
(function() {
	var _targetList = new G.Utils.List();
	var _resizeTimer = null;
	var _CHECK_INTERVAL = 200;

	var _check_resize = function() {
		for (var n = _targetList.head; n != null; n = n.next) {
			var obj = n.data;
			var w = obj.em.clientWidth;
			var h = obj.em.clientHeight;

			if (w != obj.currWidth || h != obj.currHeight) {
				obj.fire("onresize", {'w': w, 'h': h });
				obj.currWidth = w;
				obj.currHeight = h;
			}
		}
	}

	/**
	 * Regist the DomElement to system to check the resize event.
	 * @method reg_resize_check
	 */
	G.DOM.Element.prototype.reg_resize_check = function() {

		this.currWidth = this.em.clientWidth;
		this.currHeight = this.em.clientHeight;

		for (var n = _targetList.head; n != null; n = n.next) {
			if (n.data == this) {
				return;
			}
		}

		var n = new G.Utils.ListNode(this);
		_targetList.append(n);

		if (!_resizeTimer) {
			_resizeTimer = setInterval(_check_resize, _CHECK_INTERVAL);
		}
	}

	/**
	 * Stop check the resize event of the element.
	 * @method unreg_resize_check
	 */
	G.DOM.Element.prototype.unreg_resize_check = function() {
		for (var n = _targetList.head; n != null; n = n.next) {
			if (n.data == this) {
				_targetList.remove(n);
				break;
			}
		}

		if (_targetList.is_empty()) {
			clearInterval(_resizeTimer);
			_resizeTimer = null;
		}
	}
}());




